<?php


namespace custom;

use think\Exception;

class Mongo {
    /**
     * 当前对象
     * @var
     */
    protected static $instance;

    protected static $manager;

    protected static $bulk;

    protected static $writeConcern;

    /**
     * 配置定义
     * @var array
     */
    private static $configs = [
        'host'     => 'mhost',
        'port'     => 27017,
        'username' => '',
        'password' => '',
    ];

    private static $isConfig = false;

    //数据库
    public $dbname;

    /**
     * 初始化
     */
    private function __construct() {
        self::setOption();
        $conf = self::$configs;
        $this->dbname = $conf['dbname'];
        self::$manager = new \MongoDB\Driver\Manager("mongodb://username:password@{$conf['host']}:{$conf['port']}/{$this->dbname}", $conf);
    }

    /**
     * 查询
     * @param $dbname
     * @param $set
     * @return array
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function select($set, array $filter, array $options): array {
        $query = new \MongoDB\Driver\Query($filter, $options);
        $cursor = self::$manager->executeQuery("$this->dbname.$set", $query);
        return $cursor->toArray();
    }

    /**
     * 总条数
     * @param $dbname
     * @param $set
     * @param array $filter
     * @return int
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function getCount($set, array $filter): int {
        $command = new \MongoDB\Driver\Command(['count' => $set, 'query' => $filter]);
        $result = self::$manager->executeCommand($this->dbname, $command);
        $res = $result->toArray();
        $cnt = 0;
        if ($res) $cnt = $res[0]->n;
        return $cnt;
    }

    /**
     * 分页
     * @param $filter
     * @param $page
     * @param $long
     * @param $set
     * @param $sort
     * @return mixed
     * @throws \MongoDB\Driver\Exception\Exception
     */
    public function page($filter, $page, $long, $set, $sort) {
        $count = $this->getCount($set, $filter);//总条数
        $pageNum = ceil($count / $long);//总页数
        $skip = ($page - 1) * $long;
        $options = [
            'skip'  => $skip,
            'limit' => $long,
            'sort'  => $sort
        ];
        $data['data'] = $this->select($set, $filter, $options);
        $data['pageNum'] = $pageNum;
        $data['count'] = $count;
        $data['page'] = $page;
        return $data;
    }

    /**
     * 设置配置
     * @param array $config
     */
    public static function setOption($config = []) {
        if (!empty($config)) {
            self::$isConfig = true;
            self::$configs = $config;
            return true;
        }

        if (!self::$isConfig && !empty(config('db.mongo'))) {
            self::$configs = config('db.mongo');
            return true;
        }

        return true;
    }

    public static function getInstance() {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 新增
     * @param array $data [description]
     * @param [type] $tableName [description]
     */
    public function add(array $data, $tableName) {
        self::$bulk = new \MongoDB\Driver\BulkWrite;
        self::$writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 0);
        $res = (array)(self::$bulk->insert($data));
        self::$manager->executeBulkWrite("$this->dbname.$tableName", self::$bulk, self::$writeConcern);
        return $res[0];
    }

    /**
     * 批量添加
     * @param array $data [description]
     * @param [type] $tableName [description]
     * @param [type] $type      [description]
     */
    public function addAll(array $data, $tableName, $type = 'count') {
        $suc = 0;
        $id = [];
        $bulk = new \MongoDB\Driver\BulkWrite;
        $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 0);
        foreach ($data as $v) {
            $v = (array)$v;
            if (is_array($v)) {
                $res = (array)($bulk->insert($v));
                $id[] = $res['oid'];
                $suc++;
            }
        }
        self::$manager->executeBulkWrite("$this->dbname.$tableName", $bulk, $writeConcern);
        switch ($type) {
            case 'count':
                return $suc;
                break;
            default:
                return $id;
                break;
        }
    }

    /**
     * 删除
     * @param $where
     * @param $limit
     * @param $tableName
     */
    public function deldoc($where, $limit, $tableName) {
        $bulk = new \MongoDB\Driver\BulkWrite;
        $res = $bulk->delete($where, $limit);
        $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000);
        self::$manager->executeBulkWrite("$this->dbname.$tableName", $bulk, $writeConcern);
        return $res;
    }

    /**
     * 更新
     * @param $tableName
     * @param $where
     * @param $data
     * @return \MongoDB\Driver\WriteResult
     */
    public function update($tableName, $where, $data) {
        $bulk = new \MongoDB\Driver\BulkWrite;
        $bulk->update(
            $where,
            ['$set' => $data],
            ['multi' => true, 'upsert' => false]
        );
        $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000);
        $result = self::$manager->executeBulkWrite("$this->dbname.$tableName", $bulk, $writeConcern);
        return $result;
    }

}
